<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script>
        //       let不允许在相同作用域中，重复声明同一个变量 ES6块级作用域必须用大括号 
        // function fn(){
        //     let a = 1
        //     var a = 2
        // }报错
        // function func() {
        //  let a = 10;
        //  let a = 1;
        // }报错
        // 在代码块内，使用let命令声明变量之前，该变量都是不可用的。这在语法上，称为“暂时性死区”（temporal dead zone，简称 TDZ）。
       

        // if(true){
        //     console.log(sum)
        //     const sum = 0
        // } Cannot access 'sum' before initialization
        // const命令声明的常量也是不提升，同样存在暂时性死区，变量指向的那个内存地址所保存的数据不得改动
       
        

        // function f() { console.log('I am outside!'); }

        // (function () {
        //      if (false) {
        //         // 重复声明一次函数f
        //          function f() { console.log('I am inside!'); }
        // }
        //     f();
        // }());
        //报错f is not a function
         
         
         if(true){
            const a = [];
            a.length = 0;    // 可执行
            a.push('Hello'); // 可执行
            //a= [1,2,3]  //Assignment to constant variable.
            const foo = Object.freeze({});
            // 常规模式时，下面一行不起作用；
            // 严格模式时，该行会报错
            foo.prop = 123;
         }       

         var a = 1
         console.log(window.a)//1
         let b = 2
         console.log(window.b)//undefined
         //全局变量将逐步与顶层对象的属性脱钩。
        //  ES2020 在语言标准的层面，引入globalThis作为顶层对象。也就是说，任何环境下，globalThis都是存在的，都可以从它拿到顶层对象，指向全局环境下的this。


         //模式解构 
        let [c,d ,e ] = [1, 2, 3]
        console.log(c,d,e)
        //解构赋值允许指定默认值。
        let [x, y = 'b'] = ['a', undefined]
        console.log(x,y)

        var f2=()=>{alert("666")}
        let [o=f2()]=[1]//因为有赋值所以alter不会执行
         
        // 而对象的属性没有次序，变量必须与属性同名，才能取到正确的值
        let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
        console.log(foo,bar)

        // let{foo1:bra} = {foo:'aaa',bar:'bbb'}
        // console.log(foo1,bra)// foo1 is not defined foo1是匹配的模式，baz才是变量。真正被赋值的是变量baz，而不是模式foo。
        
        let { first: f, last: l } = { first: 'hello', last: 'world' };
        console.log(f,l)
        
        //解构也可以用于嵌套结构的对象。
       let obj = {
           p:[
               'Hello',
               {n:"World"}
           ]
       }
       let {p:[m,{n}]} = obj
       console.log(m,n)

       const node = {
            loc: {
                start: {
                line: 1,
                column: 5
                }
            }
        };
        let { loc, loc: { start }, loc: { start: { line }} } = node;

    
        const obj1 = {};
        const obj2 = { foo: 'bar' };
        Object.setPrototypeOf(obj1, obj2);
        const { foo2 } = obj1;
        console.log(foo2)//对象obj1的原型对象是obj2。foo属性不是obj1自身的属性，而是继承自obj2的属性，解构赋值可以取到这个属性

        //如果要将一个已经声明的变量用于解构赋值，必须非常小心
        let z;
        //{x} = {x: 1};//{x}理解成一个代码块
        ({z} = {z:1})//正确写法

        //数组本质是特殊的对象，因此可以对数组进行对象属性的解构。
        let arr = [1,2,3]
        let {0:first,[arr.length-1]:last} = arr
        console.log(first,last)


        //字符串也可以解构赋值
        var [g,h,i,j,k]="Hello"
        console.log(g,h,i,j,k)
        //解构赋值时，如果等号右边是数值和布尔值，则会先转为对象。 
        let {toString:q} = 123
        q === Number.prototype.toString
        let {toString:p} = false
        p === Boolean.prototype.toString
        console.log(q,p)   
    /*只要等号右边的值不是对象或数组，就先将其转为对象。*/

    //    函数的参数也可以使用解构赋值,可以设置默认值
        function add({x=5, y}){
        return x + y;
        }
        console.log(add({x:undefined, y:2}))

        /*以下三种解构赋值不得使用圆括号。

        (1)变量声明语句
        (2)函数参数
        (3)赋值语句的模式*/

        //提取json数据
        let jsonData = {
            id:888,
            status:"OK",
            data:[7,6]
        }
        let {id,status,data} = jsonData
        console.log(id,status,data)

        //结构遍历遍历 Map 结构
        const map  = new Map();
        map.set('vvv','hello')
        map.set('uuu','world')
        for(let [key,value] of map){
            console.log(key + ":" + value)//可以取出键值对
        }

        //promise使用
        new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve('aaa')
            },1000)
        }).then((res)=>{
            console.log(res,"第一次调用")
            return new Promise((resolve,reject)=>{
                    resolve(res+'bbb')
            }).then((res)=>{
                console.log(res,"第二次调用")
                return new Promise((resolve,reject)=>{
                    resolve(res+'ccc')
            }).then((res)=>{
                console.log(res,"第三次调用")
            })
            })
        })
        // 对上面的简写 省略new Promise
        new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve('xxx')
            },1000)
        }).then((res)=>{
            console.log(res,'第一次')
            return Promise.resolve(res+'yyy')
        }).then((res)=>{
            console.log(res,'第二次')
            return Promise.resolve(res+'zzz')
        })
         // 再对对上面的简写 Promise resolve
         new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve('ooo')
            },1000)
        }).then((res)=>{
            console.log(res,'第一次')
            return (res+'mmm')
        }).then((res)=>{
            console.log(res,'第二次')
            return (res+'nnn')
        })
        //promise异常抛出
        new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve('666')
            },1000)
        }).then((res)=>{
            console.log(res,'第一次')
            // return new Promise((resolve,reject)=>
            //     reject('err'))
            throw '错误信息'//抛出错误信息
            }).then((res)=>{
            console.log(res,'第二次')
            return (res+'888')
        }).then((res)=>{
            console.log(res,'第三次')
            return (res+'999')
        }).catch(err=>{
            console.log(err)
        })
        //promise all方法使用 接受的数据
        Promise.all([
            new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    // resolve('result1')
                     resolve({name:"zhangsan",age:18})
                },2000)
            }),
            new Promise((resolve,reject)=>{
                setTimeout(() => {
                    // resolve('result2')
                     resolve({name:"lisi",age:22})
                }, 3000);
            })
        ]).then(results=>{
            console.log(results)
        })
        
    </script>
</body>
</html>